<?php if (!defined('TL_ROOT')) die('You can not access this file directly!');

/**
 * TYPOlight webCMS
 *
 * The TYPOlight webCMS is an accessible web content management system that 
 * specializes in accessibility and generates W3C-compliant HTML code. It 
 * provides a wide range of functionality to develop professional websites 
 * including a built-in search engine, form generator, file and user manager, 
 * CSS engine, multi-language support and many more. For more information and 
 * additional TYPOlight applications like the TYPOlight MVC Framework please 
 * visit the project website http://www.typolight.org.
 *
 * PHP version 5
 * @copyright  Martin Komara, Thyon Design 2008
 * @author     Martin Komara, John Brand <john.brand@thyon.com> 
 * @package    CatalogModule 
 * @license    GPL 
 * @filesource
 */


/**
 * Class ModuleCatalog 
 *
 * @copyright  Martin Komara 2007 
 * @author     Martin Komara 
 * @package    Controller
 */
class Catalog extends Backend
{

/**
 * Callbacks: tl_catalog_types 
 */

	protected $createTableStatement = "
			CREATE TABLE `%s` (
				`id` int(10) unsigned NOT NULL auto_increment,
				`pid` int(10) unsigned NOT NULL,
				`sorting` int(10) unsigned NOT NULL default '0',
				`tstamp` int(10) unsigned NOT NULL default '0',
				PRIMARY KEY  (`id`)
			) ENGINE=MyISAM DEFAULT CHARSET=utf8";

	protected $renameTableStatement = "ALTER TABLE `%s` RENAME TO `%s`";
	protected $dropTableStatement = "DROP TABLE `%s`";
        

	public function renameTable($varValue, DataContainer $dc)
	{
		if (!preg_match('/^[a-z_][a-z\d_]*$/iu', $varValue))
		{
			throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['invalidTableName'], $varValue));
		}
		
		$objType = $this->Database->prepare("SELECT tableName, noTable FROM tl_catalog_types WHERE id=?")
				->limit(1)
				->execute($dc->id);
				
		if ($objType->numRows == 0)
		{
			return $varValue;
		}
		
		if ($objType->noTable)
		{
			if (!$this->Database->tableExists($varValue))
			{
					throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['tableDoesNotExist'], $varValue));
			}
			return $varValue;
		}
				
		$oldTableName = $objType->tableName;
				
		if (strlen($oldTableName))
		{
			$statement = sprintf($this->renameTableStatement, $oldTableName, $varValue);
		}
		else
		{
			$statement = sprintf($this->createTableStatement, $varValue);
		}
		
		$needToCheckIfExists = (!strlen($oldTableName) || $oldTableName != $varValue);
		
		if ($needToCheckIfExists && $this->Database->tableExists($varValue))
		{
			throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['tableExists'], $varValue)); 
		}
		
		$this->Database->execute($statement);
		
		$this->checkCatalogFields($dc->id, $varValue);
		
		return $varValue;
	}



	public function dropTable($tableName)
	{
		$this->Database->execute(sprintf($this->dropTableStatement, $tableName));
	}


/**
 * Callbacks: tl_catalog_fields 
 */

	protected $sqlDefColumn = array
	(
		'text'			=> "varchar(255) NOT NULL default ''",
		'alias'			=> "varchar(64) NOT NULL default ''",
		'longtext'	=> "text NULL",
		'number'		=> 'int(10) NULL default NULL',
		'decimal'		=> 'double NULL default NULL',
		'date'			=>	"int(10) unsigned NOT NULL default '0'",
		'select'		=> "int(10) NOT NULL default 0",
		'tags'			=> "text NULL",
		'checkbox'	=> "char(1) NOT NULL default ''",
		'url'				=> "varchar(255) NOT NULL default ''",
		'file'			=> "text NULL",
		'taxonomy'	=> "text NULL",
	);
	
	protected $systemColumns = array('id', 'pid', 'sorting', 'tstamp');
	
	protected $renameColumnStatement = "ALTER TABLE %s CHANGE COLUMN %s %s %s";
	
	protected $createColumnStatement = "ALTER TABLE %s ADD %s %s";
	
	protected $dropColumnStatement = "ALTER TABLE %s DROP COLUMN %s";
	


	protected function checkCatalogFields($pid, $newTableName)
	{
	
		$objFields = $this->Database->prepare("SELECT t.tableName, t.id, t.noTable, f.type, f.colName FROM tl_catalog_fields f INNER JOIN tl_catalog_types t ON f.pid=t.id WHERE t.id=? ORDER BY sorting")
			->execute($pid);
			
		while ($objFields->next())
		{	
			$tableName = strlen($newTableName) ? $newTableName : $objFields->tableName;
			$colName = $objFields->colName;
			$fieldType = $objFields->type ? $objFields->type : 'text';
			
			if (!preg_match('/^[a-z_][a-z\d_]*$/i', $colName))
			{
					throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['invalidColumnName'], $colName));
			}
			if (in_array($colName, $this->systemColumns))
			{
				throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['systemColumn'], $colName));
			}
	
			if ($this->Database->fieldExists($colName, $tableName))
			{
				$statement = sprintf($this->renameColumnStatement, $tableName, $colName, $colName, $this->sqlDefColumn[$fieldType]);
			}
			else
			{
				$statement = sprintf($this->createColumnStatement, $tableName, $colName, $this->sqlDefColumn[$fieldType]);
			}
			
			$this->Database->execute($statement);
		}
		
	}

	
	public function renameColumn($varValue, DataContainer $dc)
	{
		if (!preg_match('/^[a-z_][a-z\d_]*$/i', $varValue))
		{
			throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['invalidColumnName'], $varValue));
		}
		if (in_array($varValue, $this->systemColumns))
		{
			throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['systemColumn'], $varValue));
		}
		
		$objField = $this->Database->prepare("SELECT t.id, t.tableName, t.noTable, f.type, f.colName FROM tl_catalog_fields f INNER JOIN tl_catalog_types t ON f.pid=t.id WHERE f.id=?")
				->limit(1)
				->execute($dc->id);

		if (!$objField->numRows)
		{
			return $varValue;
		}
				
		if ($objField->noTable)
		{
			if (!$this->Database->fieldExists($varValue, $tableName))
			{
				throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['columnDoesNotExist'], $varValue, $tableName));
			}
			
			return $varValue; 
		}
				
		$tableName = $objField->tableName;
		$oldColName = $objField->colName;
		$fieldType = $objField->type ? $objField->type : 'text';
		
		$objItems = $this->Database->prepare("SELECT COUNT(*) as itemCount FROM tl_catalog_fields WHERE pid=? AND id<>? AND colName=?")
				->limit(1)
				->execute($objField->id, $dc->id, $varValue);
		
		if ($objItems->itemCount > 0)
		{
			throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['columnExists'], $varValue)); 
		}
		
		$objOld = $this->Database->prepare("SELECT COUNT(*) as itemCount FROM tl_catalog_fields WHERE pid=? AND id<>? AND colName=?")
				->limit(1)
				->execute($objField->id, $dc->id, $oldColName);

		if ($objOld->itemCount == 0 && $this->Database->fieldExists($oldColName, $tableName))
		{
			$statement = sprintf($this->renameColumnStatement, $tableName, $oldColName, $varValue, $this->sqlDefColumn[$fieldType]);
		}
		else
		{
			$statement = sprintf($this->createColumnStatement, $tableName, $varValue, $this->sqlDefColumn[$fieldType]);
		}
		
		$this->Database->execute($statement);
		
		return $varValue;
	}
	

	public function changeColumn($varValue, DataContainer $dc)
	{
		$objField = $this->Database->prepare("SELECT f.colName, f.type, t.tableName, t.noTable FROM tl_catalog_fields f INNER JOIN tl_catalog_types t ON f.pid = t.id WHERE f.id=?")
				->limit(1)
				->execute($dc->id);
				
		if ($objField->numRows == 0 || $objField->noTable)
		{
			return $varValue;
		}
		
		$tableName = $objField->tableName;
		$colName = $objField->colName;
		$fieldType = $objField->type;
		
		if ($varValue != $fieldType)
		{
			$this->dropColumn($tableName, $colName);
			$this->Database->execute(sprintf($this->createColumnStatement, $tableName, $colName, $this->sqlDefColumn[$varValue]));
		}
		
		return $varValue;
	}
	
	public function deleteColumn($ids)
	{
			$objType = $this->Database->prepare("SELECT f.colName, t.tableName, t.noTable FROM tl_catalog_fields f INNER JOIN tl_catalog_types t ON f.pid = t.id WHERE f.id IN (?)")
					->execute(implode(',', $ids));
							
			while ($objType->next())
			{
					$colName = $objType->colName;
					$tableName = $objType->tableName;
					$noTable = $objType->noTable;
					
					if ($noTable)
					{
							continue;
					}
							
					if ($this->Database->fieldExists($colName, $tableName))
					{
							$this->dropColumn($tableName, $colName);
					}
			}
	}
	
	public function dropColumn($tableName, $colName)
	{
			$this->Database->execute(sprintf($this->dropColumnStatement, $tableName, $colName));
	}



/**
 * DCA Update functions 
 */


	private $tableNames	= array();
	private $strFormat	= array();
	
	protected $fieldDef = array
	(
		'text'          => array
		(
			'inputType' => 'text'
		),
		
		'alias'          => array
		(
			'inputType' => 'text',
			'eval'      => array('rgxp'=>'alnum', 'unique'=>true, 'spaceToUnderscore'=>true, 'maxlength'=>64),
		),

		'longtext'      => array
		(
			'inputType' => 'textarea'
		),
		
		'number'        => array
		(
			'inputType' => 'text',
			'eval'      => array('rgxp' => 'digit')
		),
		
		'decimal'        => array
		(
			'inputType' => 'text',
			'eval'      => array('rgxp' => 'digit')
		),
		
		'date'          => array
		(
			'inputType' => 'text',
		),
		
		'select'        => array
		(
			'inputType' => 'select',
		),
		
		'tags'          => array
		(
			'inputType' => 'checkbox',
			'eval'      => array('multiple' => true)
		),
		
		'checkbox'      => array
		(
			'inputType' => 'checkbox',
		),
		
		'url'           => array
		(
			'inputType' => 'text',
		),
		
		'file'          => array
		(
			'inputType' => 'fileTree',
			'eval'      => array('files' => true),
		),

		'taxonomy'          => array
		(
			'inputType' => 'tableTree',
			'eval'      => array('fieldType' => 'radio', 'tableColumn'=> 'tl_taxonomy.name'),
		),


	);
    
	public function getDefaultDca()
	{
		$this->loadLanguageFile('tl_catalog_items');
		return array
		(
			'config' => array
			(
				'dataContainer'               => 'Table',
				'ptable'                      => 'tl_catalog_types',
				'switchToEdit'                => true, 
				'enableVersioning'            => false,
				'onload_callback'							=> array 
					(
						array('Catalog', 'checkPermission')
					),
			),
			
			'list' => array
			(
				'sorting' => array
				(
					'mode'                    => 2, // 2 Records are sorted by a switchable sorting value
					'flag'										=> 1, // 1 Sort by initial letter ascending
					'panelLayout'             => 'filter,limit;search,sort',
					'headerFields'            => array('name', 'tstamp'),
					'fields'            			=> array(),
					'child_record_callback'   => array('Catalog', 'renderField')
				),
				'global_operations' => array
				(
					'export' => array
					(
						'label'               => &$GLOBALS['TL_LANG']['tl_catalog_items']['export'],
						'href'                => 'key=export',
						'class'               => 'header_css_export',
						'attributes'          => 'onclick="Backend.getScrollOffset();"'
					),
					'all' => array
					(
						'label'               => &$GLOBALS['TL_LANG']['MSC']['all'],
						'href'                => 'act=select',
						'class'               => 'header_edit_all',
						'attributes'          => 'onclick="Backend.getScrollOffset();"'
					)
				),
				
				'operations' => array
				(
					'edit' => array
					(
						'label'               => &$GLOBALS['TL_LANG']['tl_catalog_items']['edit'],
						'href'                => 'act=edit',
						'icon'                => 'edit.gif',
					),
					'copy' => array
					(
						'label'               => &$GLOBALS['TL_LANG']['tl_catalog_items']['copy'],
						'href'                => 'act=copy',
						'icon'                => 'copy.gif'
					),
					'cut' => array
					(
						'label'               => &$GLOBALS['TL_LANG']['tl_catalog_items']['cut'],
						'href'                => 'act=paste&amp;mode=cut',
						'icon'                => 'cut.gif',
						'attributes'          => 'onclick="Backend.getScrollOffset();"'
					), 
					'delete' => array
					(
						'label'               => &$GLOBALS['TL_LANG']['tl_catalog_items']['delete'],
						'href'                => 'act=delete',
						'icon'                => 'delete.gif',
						'attributes'          => 'onclick="if (!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\')) return false; Backend.getScrollOffset();"'
					),
					'show' => array
					(
						'label'               => &$GLOBALS['TL_LANG']['tl_catalog_items']['show'],
						'href'                => 'act=show',
						'icon'                => 'show.gif'
					)
				),
			),
			
			'palettes' => array
			(
			),
			
			'subpalettes' => array
			(
			),
			
			'fields' => array
			(
			)
		);
	}
    
 	public function updateDCA(DataContainer $dc)
	{
		$objParent = $this->Database->prepare("SELECT pid FROM tl_catalog_fields WHERE id=?")
				->limit(1)
				->execute($dc->id);
				
		if ($objParent->numRows != 0)
		{
			$this->regenerateDca($objParent->pid);
		}
	}
   

	/**
	 * Check permissions to edit catalog tableName
	 * @param object
	 */

	public function checkPermission(dataContainer $dc)
	{

		$this->import('BackendUser', 'User');

		if ($this->User->isAdmin)
		{
			return;
		}

		// Set root IDs
		if (!is_array($this->User->catalogs) || count($this->User->catalogs) < 1)
		{
			$root = array(0);
		}
		else
		{
			$root = $this->User->catalogs;
		}

		$id = strlen($this->Input->get('id')) ? $this->Input->get('id') : CURRENT_ID;

		
		// Check current action
		switch ($this->Input->get('act'))
		{
			case 'select':
			case 'paste':
				// Allow
				break;

			case 'create':

				$checkid = $this->Input->get('id');
				if ($this->Input->get('mode') == 2 && strlen($this->Input->get('pid')) && !strlen($this->Input->get('id')))
				{
					// sorted mode
					$checkid = $this->Input->get('pid');
				}


				if (!strlen($checkid) || !in_array($checkid, $root))
				{
					$this->log('Not enough permissions to create catalog items in catalog type ID "'.$checkid.'"', 'Catalog checkPermission', 5);
					$this->redirect('typolight/main.php?act=error');
				}
				break;

			case 'edit':
			case 'show':
			case 'create':
			case 'copy':
			case 'cut':
			case 'delete':

				$rows = 0;
				$objTable = $this->Database->prepare("SELECT tableName FROM tl_catalog_types WHERE id=?")
						->limit(1)
						->execute(CURRENT_ID);
				if ($objTable->numRows) 
				{
					$tableName = $objTable->tableName;
					$objType = $this->Database->prepare("SELECT pid FROM ".$tableName." WHERE id=?")
											 ->limit(1)
											 ->execute($id);
					$rows = $objType->numRows;
				}

				if ($rows < 1)
				{
					$this->log('Invalid catalog item ID "'.$id.'"', 'Catalog checkPermission', 5);
					$this->redirect('typolight/main.php?act=error');
				}

				if (!in_array($objType->pid, $root))
				{
					$this->log('Not enough permissions to '.$this->Input->get('act').' catalog item ID "'.$id.'" of catalog type ID "'.$objType->pid.'"', 'Catalog checkPermission', 5);
					$this->redirect('typolight/main.php?act=error');
				}
				break;

			case 'editAll':
			case 'deleteAll':
				if (!in_array($id, $root))
				{
					$this->log('Not enough permissions to access catalog type ID "'.$id.'"', 'Catalog checkPermission', 5);
					$this->redirect('typolight/main.php?act=error');
				}

				$rows = 0;
				$objTable = $this->Database->prepare("SELECT tableName FROM tl_catalog_types WHERE id=?")
						->limit(1)
						->execute(CURRENT_ID);
				if ($objTable->numRows) 
				{
					$tableName = $objTable->tableName;
					$objType = $this->Database->prepare("SELECT id FROM ".$tableName." WHERE pid=?")
											 ->execute($id);
					$rows = $objType->numRows;
				}

				if ($rows < 1)
				{
					$this->log('Invalid catalog type ID "'.$id.'"', 'Catalog checkPermission', 5);
					$this->redirect('typolight/main.php?act=error');
				}

				$session = $this->Session->getData();
				$session['CURRENT']['IDS'] = array_intersect($session['CURRENT']['IDS'], $objType->fetchEach('id'));
				$this->Session->setData($session);
				break;

			default:
				if (strlen($this->Input->get('act')))
				{
					$this->log('Invalid command "'.$this->Input->get('act').'"', 'Catalog checkPermission', 5);
					$this->redirect('typolight/main.php?act=error');
				}
				if (!in_array($id, $root))
				{
					$this->log('Not enough permissions to access catalog type ID "'.$id.'"', 'Catalog checkPermission', 5);
					$this->redirect('typolight/main.php?act=error');
				}
				break;
		}
	}

 
	/**
	 * Autogenerate a catalog alias if it has not been set yet
	 * @param mixed
	 * @param object
	 * @return string
	 */
	public function generateAlias($varValue, DataContainer $dc)
	{
		$objField = $this->Database->prepare("SELECT pid FROM ".$dc->table." WHERE id=?")
				->limit(1)
				->execute($dc->id);
				
		if (!$objField->numRows)
		{
			throw new Exception($GLOBALS['TL_LANG']['ERR']['aliasTitleMissing']);
		}		
		$pid = $objField->pid;

		$objAliasTitle = $this->Database->prepare("SELECT aliasTitle FROM tl_catalog_fields WHERE pid=? AND type=?")
									   ->limit(1)
									   ->execute($pid, 'alias');

		if ($objAliasTitle->numRows)
		{
			$aliasTitle = $objAliasTitle->aliasTitle;
		}
		else
		{
			throw new Exception($GLOBALS['TL_LANG']['ERR']['aliasTitleMissing']);
		}

		$autoAlias = false;

		// Generate alias if there is none
		if (!strlen($varValue))
		{
			$objTitle = $this->Database->prepare("SELECT ".$aliasTitle." FROM ".$dc->table." WHERE id=?")
									   ->limit(1)
									   ->execute($dc->id);

			$autoAlias = true;
			$varValue = standardize($objTitle->$aliasTitle);
		}

		$objAlias = $this->Database->prepare("SELECT id FROM ".$dc->table." WHERE ".$aliasTitle."=?")
								   ->execute($varValue);

		// Check whether the catalog alias exists
		if ($objAlias->numRows > 1 && !$autoAlias)
		{
			throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['aliasExists'], $varValue));
		}

		// Add ID to alias
		if ($objAlias->numRows && $autoAlias)
		{
			$varValue .= '.' . $dc->id;
		}

		return $varValue;
	}

	/**
	 * Add the type of input field
	 * @param array
	 * @return string
	 */
	public function listCatalogItems($arrRow)
	{
		$key = $arrRow['published'] ? 'published' : 'unpublished';
		$date = date($GLOBALS['TL_CONFIG']['datimFormat'], $arrRow['date']);

		return '
<div class="cte_type ' . $key . '"><strong>' . $arrRow['headline'] . '</strong> - ' . $date . '</div>
<div class="limit_height' . (!$GLOBALS['TL_CONFIG']['doNotCollapse'] ? ' h64' : '') . ' block">
' . $arrRow['text'] . '
</div>' . "\n";
	}    
    


	public function saveTags($varValue, DataContainer $dc)
	{
			$options = @deserialize($varValue);
			if (!is_array($options))
			{
					$options = array();
			}
	
			$fieldId = $GLOBALS['TL_DCA'][$dc->table]['fields'][$dc->field]['eval']['catalog']['fieldId'];
			if ($fieldId)
			{
					$this->Database->prepare("DELETE FROM tl_catalog_rel WHERE item_id=? AND field_id=?")->execute($dc->id, $fieldId);
					
					foreach ($options as $option)
					{
							$this->Database->prepare("INSERT INTO tl_catalog_rel %s")
									->set(array('item_id' => $dc->id, 'field_id' => $fieldId, 'related_id' => $option))
									->execute();
					}
			}
			
			return join(',', $options);
	}
	
	public function loadTags($varValue, DataContainer $dc)
	{
			return serialize(split(',', $varValue));
	}
    
	public function dcaLoadOptions(DataContainer $dc)
	{
			$catConfig = $GLOBALS['TL_DCA'][$dc->table]['fields'][$dc->field]['eval']['catalog'];
			
			// check if we need to load items
			$needToUpdate = !$catConfig['limitItems'] || $catConfig['childrenSelMode'];
			return $needToUpdate ?
					$this->loadOptions($catConfig['foreignKey'], $catConfig['limitItems'], $catConfig['childrenSelMode'], $catConfig['selectedIds'], $catConfig['sortCol']) :
					$GLOBALS['TL_DCA'][$dc->table]['fields'][$dc->field]['options'];
	}


/**
 * Row Label
 */	
    
	public function renderField($row)
	{
	
		if (!$row['pid'])
		{
			return 'ID:'.$row['id'];
		}

		if (isset($this->tableNames[$row['pid']]) && isset($this->strFormat[$row['pid']]))
		{
			$tableName = $this->tableNames[$row['pid']];
			$strFormat = $this->strFormat[$row['pid']];
		}
		else
		{
			$objType = $this->Database->prepare("SELECT tableName, format FROM tl_catalog_types WHERE id=?")
					->limit(1)
					->execute($row['pid']);
			
			$tableName = $objType->tableName;
			$strFormat = $objType->format;
			$this->tableNames[$row['pid']] = $tableName;
			$this->strFormat[$row['pid']] = $strFormat;
		}
		
		$fields = $GLOBALS['TL_DCA'][$tableName]['list']['label']['fields'];

		$values = array();
		foreach($fields as $field)
		{
			$values[$field] = $this->formatTitle($row[$field], $GLOBALS['TL_DCA'][$tableName]['fields'][$field]);
		}

		if (!strlen($strFormat))
		{
			return implode(', ', $values);
		}
		else
		{
			return $this->generateTitle($strFormat, $values, $tableName);
		}
	}


	private function generateTitle($strFormat, $values, $tableName)
	{
		$fields = $GLOBALS['TL_DCA'][$tableName]['list']['label']['fields'];
		preg_match_all('/{{([^}]+)}}/', $strFormat, $matches);
		//$strFormat = '';
		foreach ($matches[1] as $match)
		{
			$params = split('::', $match);
			$fieldConf = $GLOBALS['TL_DCA'][$tableName]['fields'][$params[0]];
			if ($fieldConf)
			{	
				$replace = $values[$params[0]];
				if ($params[1])
				{
					switch ($fieldConf['eval']['catalog']['type'])
					{
						case 'file':
								if ($fieldConf['eval']['catalog']['showImage'])
								{ 
									$replace = $this->generateThumbnail($replace, $params[1], $fieldConf['label'][0]);
								}
								break;

						case 'checkbox':
								// only use image if checkbox == true
								$replace = ($replace ? $this->generateThumbnail($replace, $params[1], $fieldConf['label'][0]) : '');
								break;

						default:;

					}					
				}
				$strFormat = str_replace('{{'.$match.'}}', $replace, $strFormat);
			}
		}
		return $strFormat;
	}


	private function generateThumbnail($value, $query, $label)
	{
		// parse query parameters if set
		parse_str($query, $params);
		$src = $params['src'] ? $params['src'] :  $value;

		if (strpos($src, '/') === false)
		{
			$src = sprintf('system/themes/%s/images/%s', $this->getTheme(), $src);
		}

		if ($value == '' || !file_exists(TL_ROOT.'/'.$src))
		{
			return '';
		}

		//$size = getimagesize(TL_ROOT.'/'.$src);
		return '<img src="' . $this->getImage($src, $params['w'], $params['h']) . '" alt="'.specialchars($label).'" />';

	}
    
	private function formatTitle($value, &$fieldConf)
	{
		if (strlen($value))
		{
			switch ($fieldConf['eval']['catalog']['formatFunction'])
			{
				case 'string':
						$value = sprintf($fieldConf['eval']['catalog']['formatStr'], $value);
						break;
						
				case 'number':
						$decimalPlaces = is_numeric($fieldConf['eval']['catalog']['formatStr']) ? 
								intval($fieldConf['eval']['catalog']['formatStr']) : 
								0;
						$value = number_format($value, $decimalPlaces, 
								$GLOBALS['TL_LANG']['MSC']['decimalSeparator'],
								$GLOBALS['TL_LANG']['MSC']['thousandsSeparator']);
						break;
						
				case 'money':
						$value = money_format($fieldConf['eval']['catalog']['formatStr'], $value);
						break;
						
				case 'date':
						$value = date($fieldConf['eval']['catalog']['formatStr'], $value);
						break;
						
				default:
						if ($fieldConf['eval']['rgxp'] == 'date' || $fieldConf['eval']['rgxp'] == 'datim')
						{
								$value = date($GLOBALS['TL_CONFIG'][$fieldConf['eval']['rgxp'].'Format'], $value);
						}
			}
			
			if ($fieldConf['eval']['catalog']['type'] == 'checkbox' && $value)
			{
				$value = $fieldConf['label'][0];
			}
		}
				
		return $value;
	}


    
	public function pagePicker(DataContainer $dc)
	{
		return ' ' . $this->generateImage('pickpage.gif', $GLOBALS['TL_LANG']['MSC']['pagepicker'], 'style="vertical-align:top; cursor:pointer;" onclick="Backend.pickPage(\'ctrl_'.$dc->field.'\')"');
	}
	
	
	public function regenerateDca($typeId)
	{
			$objFields = $this->Database->prepare("SELECT * FROM tl_catalog_fields WHERE pid=? ORDER BY sorting")
						->execute($typeId);

			$this->fieldDef['date']['eval'] = array('datepicker' => $this->getDatePickerString());
			

			// load default catalog dca
			$dca = $this->getDefaultDca();        
			
			$fields = array();
			$titleFields = array();
			$sortingFields = $dca['list']['sorting']['fields'];
//			$sortingFields = array();
			$groupingFields = array();
			$selectors = array();

			// load DCA, as we're calling it now in Catalog, not tl_catalog_fields
			$this->loadDataContainer('tl_catalog_fields');			

			while ($objFields->next())
			{
					$colName = $objFields->colName;
					$colType = $objFields->type;
					
					$visibleOptions = trimsplit('[,;]', $GLOBALS['TL_DCA']['tl_catalog_fields']['palettes'][$colType]);

					$field = $this->fieldDef[$colType];
					$fields[] = $colName;
          $separators[] = (($objFields->insertBreak) ? ';' : ',');
					
					$dca['fields'][$colName] = @array_merge_recursive
					(
							array
							(
									'label'     => array ($objFields->name, $objFields->description),
									'eval'      => array 
									(
											'mandatory'         => $objFields->mandatory && in_array('mandatory', $visibleOptions) ? true : false,
											'unique'            => $objFields->uniqueItem && in_array('uniqueItem', $visibleOptions) ? true : false,
											'catalog'           => array
											(
													'type'          => $colType,
											)
									),
									'default'   => $objFields->defValue,
									'filter'    => $objFields->filteredField && in_array('filteredField', $visibleOptions) ? true : false,
									'search'    => $objFields->searchableField && in_array('searchableField', $visibleOptions) ? true : false,
									'sorting'   => $objFields->sortingField && in_array('sortingField', $visibleOptions) ? true : false,
							),
							$field
					);
					
					
					$configFunction = $colType . "Config";
					if (method_exists($this, $configFunction))
					{
							$this->$configFunction($dca['fields'][$colName], $objFields);
					}
					
					if ($objFields->titleField && in_array('titleField', $visibleOptions))
					{
							$titleFields[] = $colName;
					}
					
					if ($objFields->sortingField && in_array('sortingField', $visibleOptions))
					{
							$sortingFields[] = $colName;
							$dca['fields'][$colName]['flag'] = $objFields->groupingMode;
					}
										
					if ($objFields->parentCheckbox)
					{
							if (isset($selectors[$objFields->parentCheckbox]))
							{
									$selectors[$objFields->parentCheckbox][] = $colName;
							}
							else
							{
									$selectors[$objFields->parentCheckbox] = array($colName);
							}
					}
			}
			
			// build palettes and subpalettes
			$selectors = array_intersect_key($selectors, array_flip($fields));
			$fieldsInSubpalette = array();
			foreach ($selectors as $selector => $subpaletteFields)
			{
					$dca['fields'][$selector]['eval']['submitOnChange'] = true;
					$dca['subpalettes'][$selector] = implode(',', $subpaletteFields);
					$fieldsInSubpalette = array_merge($fieldsInSubpalette, $subpaletteFields);
			}
			$dca['palettes']['__selector__'] = array_keys($selectors);

			// added insertbreak behaviour by thyon
			$strPalette = '';
			$palettes = array_diff($fields, $fieldsInSubpalette);
			foreach ($palettes as $id=>$field) 
			{
				$strPalette .= (($id > 0) ? $separators[$id] : '').$field;	
			}
			$dca['palettes']['default'] = $strPalette;
						
			// set title fields
			$titleFields = count($titleFields) ? $titleFields : array('id');
			$titleFormat = implode(', ', array_fill(0, count($titleFields), '%s'));
			$dca['list']['label'] = array
			(
					'fields' => $titleFields, 
					'format' => $titleFormat,
					'label_callback' => array('Catalog', 'renderField'),
			);
			
			// set sorting fields
			if (count($sortingFields)) 
			{
				$dca['list']['sorting']['fields'] = $sortingFields;
				unset($dca['list']['operations']['cut']);
			}
			else 
			{
				$dca['list']['sorting']['mode'] = 4;
				$dca['list']['sorting']['fields'] = array('sorting'); 
			}
					
			$this->Database->prepare("UPDATE tl_catalog_types SET dca=? WHERE id=?")
					->execute(serialize($dca), $typeId);
	}
	
	private function numberConfig(&$field, $objRow)
	{
			$field['eval']['catalog']['minValue'] = $objRow->minValue;
			$field['eval']['catalog']['maxValue'] = $objRow->maxValue;
			
			$this->formatConfig($field, $objRow);
	}
	
	private function decimalConfig(&$field, $objRow)
	{
			$this->numberConfig($field, $objRow);
	}
	
	private function textConfig(&$field, $objRow)
	{
			$this->formatConfig($field, $objRow);
	}
	
	private function longtextConfig(&$field, $objRow)
	{
			$field['eval']['rte'] = $objRow->rte ? 'tinyMCE' : '';
	}
	
	private function selectConfig(&$field, $objRow)
	{
			$this->configOptions($field, $objRow);
	}
	
	private function tagsConfig(&$field, $objRow)
	{
		$this->configOptions($field, $objRow);
		
		$field['eval']['catalog']['fieldId'] = $objRow->id;
		
		$field['save_callback'] = array
		(
			array('Catalog', 'saveTags')
		);
		
		$field['load_callback'] = array
		(
			array('Catalog', 'loadTags')
		);
	}

	//added by thyon
	private function aliasConfig(&$field, $objRow)
	{
		$field['save_callback'] = array
		(
			array('Catalog', 'generateAlias')
		);
	}
					
	private function taxonomyConfig(&$field, $objRow)
	{
		$field['eval']['rootid'] = $objRow->taxonomyRoot;
	}

	private function configOptions(&$field, $objRow)
	{
		// due to TL bug we may not load options at runtime
		//$field['options_callback'] = array('Catalog', 'dcaLoadOptions');
		
		$foreignKey = $objRow->itemTable . '.' . $objRow->itemTableValueCol;
		$limitItems = $objRow->limitItems ? true : false;
		$childrenSelMode = $objRow->childrenSelMode ? true : false;
		$ids = unserialize($objRow->items);
		$sortCol = $objRow->itemSortCol;
		
		$field['eval']['catalog']['foreignKey'] = $foreignKey;
		$field['eval']['catalog']['limitItems'] = $limitItems;
		$field['eval']['catalog']['childrenSelMode'] = $childrenSelMode;
		$field['eval']['catalog']['selectedIds'] = $ids;
		$field['eval']['catalog']['sortCol'] = $sortCol;
		
		$needToUpdate = !$limitItems || $childrenSelMode;
		// due to TL bug we need to store options in DCA
		//$field['options'] = $needToUpdate ? 
		//    null : 
		//    $this->loadOptions($foreignKey, $limitItems, $childrenSelMode, $ids);
		$field['options'] = $this->loadOptions($foreignKey, $limitItems, $childrenSelMode, $ids, $sortCol);
	}
	
	private function loadOptions($foreignKey, $limitItems, $childrenSelMode, $ids, $sort='sorting')
	{
		$idCol = 'id';
		list($itemTable, $valueCol) = explode('.', $foreignKey);
		
		$items = array();

		if (!strlen($sort)) 
		{
			$sort = 'sorting';
		}
				
		$sortOrder = $this->Database->fieldExists($sort, $itemTable) ? $sort : $valueCol;
		
		if (!$limitItems)
		{
			$query = "SELECT $idCol, $valueCol FROM $itemTable ORDER BY $sortOrder";
			$items = $this->loadOptionsFromDb($query, $idCol, $valueCol);
		}
		else
		{
			if (is_array($ids) && count($ids) != 0)
			{
				$condCol = $childrenSelMode ? 'pid' : 'id';
				$query = sprintf("SELECT $idCol, $valueCol FROM $itemTable WHERE $condCol IN (%s) ORDER BY $sortOrder",
						implode(',', $ids));
				$items = $this->loadOptionsFromDb($query, $idCol, $valueCol);
			}
		}
		return $items;
	}
	
	private function loadOptionsFromDb($query, $idCol, $valueCol)
	{
		try
		{
				$objItems = $this->Database->execute($query);
		}
		catch (Exception $e)
		{
				return array();
		}
		
		$result = array();
		while($objItems->next())
		{
				$result[$objItems->$idCol] = $objItems->$valueCol;
		}
		return $result;
	}
	
	private function dateConfig(&$field, $objRow)
	{
		$field['eval']['rgxp'] = $objRow->includeTime ? 'datim' : 'date';
		
		$this->formatConfig($field, $objRow);
	}
	
	private function fileConfig(&$field, $objRow)
	{
		$field['eval']['catalog']['showLink'] = $objRow->showLink ? true : false;
		$field['eval']['catalog']['showImage'] = $objRow->showImage ? true : false;
					 
		$field['eval']['catalog']['imageWidth'] = $objRow->imageWidth;
		$field['eval']['catalog']['imageHeight'] = $objRow->imageHeight;
		$field['eval']['catalog']['multiple'] = $objRow->multiple;
		
		$field['eval']['fieldType'] = $objRow->multiple ? 'checkbox' : 'radio';

		if ($objRow->customFiletree)
		{
			if (strlen($objRow->uploadFolder))
			{
				$field['eval']['path'] = $objRow->uploadFolder;
			}
			if (strlen($objRow->validFileTypes)) 
			{
				$field['eval']['extensions'] = $objRow->validFileTypes;
			}
			if (strlen($objRow->filesOnly)) 
			{
				$field['eval']['filesOnly'] = true;
			}
		}
	}
	
	private function urlConfig(&$field, $objRow)
	{
		$field['eval']['rgxp'] = 'url';
		$field['wizard'] = array(array('Catalog', 'pagePicker'));
		$field['eval']['catalog']['showLink'] = $objRow->showLink ? true : false;
	}
	
	private function formatConfig(&$field, $objRow)
	{
		$field['eval']['catalog']['formatFunction'] = $objRow->format ? $objRow->formatFunction : '';
		$field['eval']['catalog']['formatStr'] = $objRow->formatStr;
	}
	
	public function regenerateAllDca()
	{
		
		$success = false;
		if ($this->Input->post('FORM_SUBMIT') == 'tl_catalog_regenerate_dca')
		{
			$objTypes = $this->Database->execute("SELECT * FROM tl_catalog_types");
	
			while ($objTypes->next())
			{
				$this->regenerateDca($objTypes->id);
			}

			$success = true;
		}
		
		// Return form
		return '
	<div id="tl_buttons">
	<a href="'.$this->getReferer(ENCODE_AMPERSANDS).'" class="header_back" title="'.specialchars($GLOBALS['TL_LANG']['MSC']['backBT']).'">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a>
	</div>
	
	<h2 class="sub_headline">'.$GLOBALS['TL_LANG']['tl_catalog_types']['regenerateDca'][1].'</h2>'.$this->getMessages().'
	
	<form action="'.ampersand($this->Environment->request, ENCODE_AMPERSANDS).'" id="tl_catalog_regenerate_dca" class="tl_form" method="post">
	<div class="tl_formbody_edit">
	<input type="hidden" name="FORM_SUBMIT" value="tl_catalog_regenerate_dca" />
	
	<div class="tl_tbox">
	<h3><label for="source">'.$GLOBALS['TL_LANG']['tl_catalog_types']['regenerateDca'][0].'</label></h3>
	<p style="line-height:16px; padding-top:6px;">'.$GLOBALS['TL_LANG']['tl_catalog_types']['regenerateDcaExplanation'].'</p>
	'.($success ? '<p class="tl_confirm">'.$GLOBALS['TL_LANG']['tl_catalog_types']['regenerateDcaSuccess'].'</p>' : '').'
	</div>
	
	</div>
	
	<div class="tl_formbody_submit">
	
	<div class="tl_submit_container">
	<input type="submit" name="save" id="save" class="tl_submit" alt="regenerate dca" accesskey="s" value="'.specialchars($GLOBALS['TL_LANG']['tl_catalog_types']['regenerateDca'][0]).'" />
	</div>
	
	</div>
	</form>';
	}


	/**
	 * Return a form to choose a CSV file and import it
	 * @param object
	 * @return string
	 */
	public function exportItems(DataContainer $dc)
	{
		if ($this->Input->get('key') != 'export')
		{
			return '';
		}
		
		$objCatalog = $this->Database->prepare("SELECT id,tableName FROM tl_catalog_types WHERE id=?")
					->limit(1)
					->execute($dc->id);

		if (!$objCatalog->numRows)
		{
			return '';
		}
		
		// get records
		$arrExport = array();
		$objRow = $this->Database->prepare("SELECT * FROM ".$objCatalog->tableName." WHERE pid=?")
					->execute($objCatalog->id);

		if ($objRow->numRows)
		{
			$arrExport = $objRow->fetchAllAssoc();			
		}

		// start output
		$exportFile =  'export_'.$objCatalog->tableName.'_' . date("Ymd-Hi");
		
		header('Content-Type: application/csv');
		header('Content-Transfer-Encoding: binary');
		header('Content-Disposition: attachment; filename="' . $exportFile .'.csv"');
		header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
		header('Pragma: public');
		header('Expires: 0');

		$output = '';
		$output .= '"'.join('","', array_keys($arrExport[0])).'"'. "\n" ;

		foreach ($arrExport as $export) 
		{
			$output .= '"' . join('","', $export).'"' . "\n";
		}

		echo $output;
		exit;

	}

	
	
}

?>